
#include	"Interpreter.hh"

Interpreter::Interpreter(Gomoku::Data &info_)
  : info(info_), bpoint(0), wpoint(0), me(0), adv(1), wwin(false), bwin(false)
{
}

void		Interpreter::run(std::map<int, GObject*> &p, int xy)
{
  int		x, y;

  x = xy / 100;
  y = xy % 100;

  this->me = 1;
  this->adv = 0;
  if (p[xy]->getId() == 0)
    {
      this->me = 0;
      this->adv = 1;

    }
  this->takePawn(p, x, y);
  for (std::map<int, GObject*>::iterator it = p.begin(); it != p.end(); it++)
    if (it->second->getId() == this->me)
      this->win5(p, it->first / 100, it->first % 100);
}

bool		Interpreter::checkPos(std::map<int, GObject*> &p, int x, int y, int player)
{
  return (p.find(x * 100 + y) != p.end() && p[x * 100 + y]->getId() == player);
}

void		Interpreter::countPawn(std::map<int, GObject*> &p, int x1, int y1, int x2, int y2)
{
  p.erase(x1 * 100 + y1);
  p.erase(x2 * 100 + y2);
  if (this->me == 0)
    this->wpoint += 2;
  else
    this->bpoint += 2;
  if (this->info.getNetwork().isConnected)
    {
      this->info.getNetwork().ServerPacket << "REM "
	+ TToString<int>(x1) + " "
	+ TToString<int>(y1) + " "
	+ TToString<int>(x2) + " "
	+ TToString<int>(y2) + "\n";
      this->info.getNetwork().Client.Send(this->info.getNetwork().ServerPacket);
      this->info.getNetwork().ServerPacket.Clear();
      std::cout << "msg envoyer" << std::endl;
    }
}

bool		Interpreter::inMap(int x, int y)
{
  return (x >= 0 && x < 19 && y >= 0 && y < 19);
}
    
//win

void		Interpreter::checkWin5(int count)
{
  if (count + 1 > 4 && this->me == 0)
    this->wwin = true;
  else if (count + 1 > 4)
    this->bwin = true;
}

void		Interpreter::win5(std::map<int, GObject*> &p, int x, int y)
{
  this->winHorizontal(p, x, y);
  this->winVertical(p, x, y);
  this->winLeftDiagonal(p, x, y);
  this->winRightDiagonal(p, x, y);
}

bool		Interpreter::VerticalTreat(std::map<int, GObject*> &p, int x, int y)
{
  if (this->inMap(x, y - 1) && this->checkPos(p, x, y - 1, this->adv) &&
      this->inMap(x, y + 1) && this->checkPos(p, x, y + 1, this->me) &&
      p.find(x * 100 + y + 2) == p.end())
    return true;
  if (this->inMap(x, y - 2) && this->checkPos(p, x, y - 2, this->adv) &&
      this->inMap(x, y - 1) && this->checkPos(p, x, y - 1, this->me) &&
      p.find(x * 100 + y + 1) == p.end())
    return true;
  if (this->inMap(x, y + 1) && this->checkPos(p, x, y + 1, this->adv) &&
      this->inMap(x, y - 1) && this->checkPos(p, x, y - 1, this->me) &&
      p.find(x * 100 + y - 2) == p.end())
    return true;
  if (this->inMap(x, y + 2) && this->checkPos(p, x, y - 2, this->adv) &&
      this->inMap(x, y + 1) && this->checkPos(p, x, y - 1, this->me) &&
      p.find(x * 100 + y + 1) == p.end())
    return true;
  return false;
}

bool		Interpreter::HorizontalTreat(std::map<int, GObject*> &p, int x, int y)
{
  if (this->inMap(x + 1, y) && this->checkPos(p, x + 1, y, this->adv) &&
      this->inMap(x - 1, y) && this->checkPos(p, x - 1, y, this->me) &&
      p.find((x - 2) * 100 + y) == p.end())
    return true;
  if (this->inMap(x + 2, y) && this->checkPos(p, x + 2, y, this->adv) &&
      this->inMap(x + 1, y) && this->checkPos(p, x + 1, y, this->me) &&
      p.find((x - 1) * 100 + y) == p.end())
    return true;
  if (this->inMap(x - 1, y) && this->checkPos(p, x - 1, y, this->adv) &&
      this->inMap(x + 1, y) && this->checkPos(p, x + 1, y, this->me) &&
      p.find((x + 2) * 100 + y) == p.end())
    return true;
  if (this->inMap(x - 2, y) && this->checkPos(p, x - 2, y, this->adv) &&
      this->inMap(x - 1, y) && this->checkPos(p, x - 1, y, this->me) &&
      p.find((x + 1) * 100 + y) == p.end())
    return true;
  return false;
}

bool		Interpreter::LeftDiagonalTreat(std::map<int, GObject*> &p, int x, int y)
{
  if (this->inMap(x - 2, y - 2) && this->checkPos(p, x - 2, y - 2, this->adv) &&
      this->inMap(x - 1, y - 1) && this->checkPos(p, x - 1, y - 1, this->me) &&
      p.find((x + 1) * 100 + y + 1) == p.end())
    return true;
  if (this->inMap(x - 1 , y - 1) && this->checkPos(p, x - 1, y - 1, this->adv) &&
      this->inMap(x + 1, y + 1) && this->checkPos(p, x + 1, y + 1, this->me) &&
      p.find((x + 2) * 100 + y + 2) == p.end())
    return true;
  if (this->inMap(x + 1, y + 1) && this->checkPos(p, x + 1, y + 1, this->adv) &&
      this->inMap(x - 1, y - 1) && this->checkPos(p, x - 1, y - 1, this->me) &&
      p.find((x - 2) * 100 + y - 2) == p.end())
    return true;
  if (this->inMap(x + 2, y + 2) && this->checkPos(p, x + 2 , y + 2, this->adv) &&
      this->inMap(x + 1, y + 1) && this->checkPos(p, x + 1, y + 1, this->me) &&
      p.find((x - 1) * 100 + y - 1) == p.end())
    return true;
  return false;
}

bool		Interpreter::RightDiagonalTreat(std::map<int, GObject*> &p, int x, int y)
{
  if (this->inMap(x + 2, y - 2) && this->checkPos(p, x + 2, y - 2, this->adv) &&
      this->inMap(x + 1, y - 1) && this->checkPos(p, x + 1, y - 1, this->me) &&
      p.find((x - 1) * 100 + y + 1) == p.end())
    return true;
  if (this->inMap(x + 1, y - 1) && this->checkPos(p, x + 1, y - 1, this->adv) &&
      this->inMap(x - 1, y + 1) && this->checkPos(p, x - 1, y + 1, this->me) &&
      p.find((x - 2) * 100 + y + 2) == p.end())
    return true;
  if (this->inMap(x - 1, y + 1) && this->checkPos(p, x - 1, y + 1, this->adv) &&
      this->inMap(x + 1, y - 1) && this->checkPos(p, x + 1, y - 1, this->me) &&
      p.find((x + 2) * 100 + y - 2) == p.end())
    return true;
  if (this->inMap(x - 2, y + 2) && this->checkPos(p, x - 2, y + 2, this->adv) &&
      this->inMap(x - 1, y + 1) && this->checkPos(p, x - 1, y + 1, this->me) &&
      p.find((x + 1) * 100 + y - 1) == p.end())
    return true;
  return false;
}

bool		Interpreter::breakableHorizontal(std::map<int, GObject*> &p, int x, int y)
{
  if (this->VerticalTreat(p, x, y) || this->LeftDiagonalTreat(p, x, y) || this->RightDiagonalTreat(p, x, y))
    return true;
  return false;
}

bool		Interpreter::breakableVertical(std::map<int, GObject*> &p, int x, int y)
{
  if (this->HorizontalTreat(p, x, y) || this->LeftDiagonalTreat(p, x, y) || this->RightDiagonalTreat(p, x, y))
    return true;
  return (false);
}

bool		Interpreter::breakableLeftDiagonal(std::map<int, GObject*>&p, int x, int y)
{
  if (this->HorizontalTreat(p, x, y) || this->VerticalTreat(p, x, y) || this->RightDiagonalTreat(p, x, y))
    return true;
  return false;
}

bool		Interpreter::breakableRightDiagonal(std::map<int, GObject*>&p, int x , int y)
{
  if (this->HorizontalTreat(p, x, y) || this->VerticalTreat(p, x, y) || this->LeftDiagonalTreat(p, x, y))
    return true;
  return false;
}

void		Interpreter::winHorizontal(std::map<int, GObject*> &p, int x, int y)
{
  int		count = 0;
  int		count_ = 0;

  for (int i = 1; i < 5 && this->inMap(x + i, y) && this->checkPos(p, x + i, y, this->me); i++, count++);
  for (int i = 1; i < 5 && this->inMap(x - i, y) && this->checkPos(p, x - i, y, this->me); i++, count_++);
  if (this->info.getRule5break())
    {
      for (int i = count ; i > 0 ; i--)
	if (breakableHorizontal(p, x + i, y))
	  return ;
      for (int i = count_; i > 0; i--)
	if (breakableHorizontal(p, x - i, y))
	  return ;
      if (this->breakableHorizontal(p, x, y))
	return ;
      
    }
  this->checkWin5(count + count_);
}

void		Interpreter::winVertical(std::map<int, GObject*> &p, int x, int y)
{
  int		count = 0;
  int		count_ = 0;

  for (int i = 1; i < 5 && this->inMap(x, y + i) && this->checkPos(p, x, y + i, this->me); i++, count++);
  for (int i = 1; i < 5 && this->inMap(x, y - i) && this->checkPos(p, x, y - i, this->me); i++, count_++);
  if (this->info.getRule5break())
    {
      for (int i = count ; i > 0 ; i--)
	if (breakableVertical(p, x, y + i))
	  return ;
      for (int i = count_; i > 0; i--)
	if (breakableVertical(p, x, y - i))
	  return ;
      if (this->breakableVertical(p, x, y))
	return ;
    }
  this->checkWin5(count + count_);
}

void		Interpreter::winLeftDiagonal(std::map<int, GObject*> &p, int x, int y)
{
  int		count = 0;
  int		count_ = 0;

  for (int i = 1; i < 5 && this->inMap(x - i, y - i) && this->checkPos(p, x - i, y - i, this->me); i++, count++);
  for (int i = 1; i < 5 && this->inMap(x + i, y + i) && this->checkPos(p, x + i, y + i, this->me); i++, count_++);
  if (this->info.getRule5break() && (count + count_) >= 4)
    {
      for (int i = count ; i > 0 ; i--)
	if (breakableLeftDiagonal(p, x - i, y - i))
	  return ;
      for (int i = count_; i > 0; i--)
	if (breakableLeftDiagonal(p, x + i, y + i))
	  return ;
      if (this->breakableLeftDiagonal(p, x, y))
	return ;
    }
  this->checkWin5(count + count_);
}

void		Interpreter::winRightDiagonal(std::map<int, GObject*> &p, int x, int y)
{
  int		count = 0;
  int		count_ = 0;

  for (int i = 1; i < 5 && this->inMap(x - i, y + i) && this->checkPos(p, x - i, y + i, this->me); i++, count++);
  for (int i = 1; i < 5 && this->inMap(x + i, y - i) && this->checkPos(p, x + i, y - i, this->me); i++, count_++);
  if (this->info.getRule5break())
    {
      for (int i = count ; i > 0 ; i--)
	if (breakableRightDiagonal(p, x - i, y + i))
	  return ;
      for (int i = count_; i > 0; i--)
	if (breakableRightDiagonal(p, x + i, y - i))
	  return ;
      if (this->breakableRightDiagonal(p, x, y))
	return ;
    }
  this->checkWin5(count + count_);
}

	       //take

void		Interpreter::takePawn(std::map<int, GObject*> &p, int x, int y)
{
  this->checkHorizontal(p, x, y);
  this->checkVertical(p, x, y);
  this->checkLeftDiagonal(p, x, y);
  this->checkRightDiagonal(p, x, y);
}

void		Interpreter::checkHorizontal(std::map<int, GObject*> &p, int x, int y)
{
  if (this->inMap(x + 3, y) &&
      this->checkPos(p, x + 1, y, this->adv) &&
      this->checkPos(p, x + 2, y, this->adv) &&
      this->checkPos(p, x + 3, y, this->me))
    this->countPawn(p, x + 1, y, x + 2, y);
  if (this->inMap(x - 3, y) &&
      this->checkPos(p, x - 1, y, this->adv) &&
      this->checkPos(p, x - 2, y, this->adv) &&
      this->checkPos(p, x - 3, y, this->me))
    this->countPawn(p, x - 1, y, x - 2, y);
}

void		Interpreter::checkVertical(std::map<int, GObject*> &p, int x, int y)
{
  if (this->inMap(x, y + 3) &&
      this->checkPos(p, x, y + 1, this->adv) &&
      this->checkPos(p, x, y + 2, this->adv) &&
      this->checkPos(p, x, y + 3, this->me))
    this->countPawn(p, x, y + 1, x, y + 2);
  if (this->inMap(x, y - 3) &&
      this->checkPos(p, x, y - 1, this->adv) &&
      this->checkPos(p, x, y - 2, this->adv) &&
      this->checkPos(p, x, y - 3, this->me))
    this->countPawn(p, x, y - 1, x, y - 2);
}

void		Interpreter::checkLeftDiagonal(std::map<int, GObject*> &p, int x, int y)
{
  if (this->inMap(x + 3, y + 3) &&
      this->checkPos(p, x + 1, y + 1, this->adv) &&
      this->checkPos(p, x + 2, y + 2, this->adv) &&
      this->checkPos(p, x + 3, y + 3, this->me))
    this->countPawn(p, x + 1, y + 1, x + 2, y + 2);
  if (this->inMap(x - 3, y - 3) &&
      this->checkPos(p, x - 1, y - 1, this->adv) &&
      this->checkPos(p, x - 2, y - 2, this->adv) &&
      this->checkPos(p, x - 3, y - 3, this->me))
    this->countPawn(p, x - 1, y - 1, x - 2, y - 2);
}

void		Interpreter::checkRightDiagonal(std::map<int, GObject*> &p, int x, int y)
{
  if (this->inMap(x - 3, y + 3) &&
      this->checkPos(p, x - 1, y + 1, this->adv) &&
      this->checkPos(p, x - 2, y + 2, this->adv) &&
      this->checkPos(p, x - 3, y + 3, this->me))
    this->countPawn(p, x - 1, y + 1, x - 2, y + 2);
  if (this->inMap(x + 3, y - 3) &&
      this->checkPos(p, x + 1, y - 1, this->adv) &&
      this->checkPos(p, x + 2, y - 2, this->adv) &&
      this->checkPos(p, x + 3, y - 3, this->me))
    this->countPawn(p, x + 1, y - 1, x + 2, y - 2);
}

int		Interpreter::getWpoint(void) const
{
  return (this->wpoint);
}

int		Interpreter::getBpoint(void) const
{
  return (this->bpoint);
}

void             Interpreter::resetPoint(void)
{
  this->wwin = false;
  this->bwin = false;
  this->wpoint = 0;
  this->bpoint = 0;
}

bool		Interpreter::getWwin(void) const
{
  return (this->wwin);
}

bool		Interpreter::getBwin(void) const
{
  return (this->bwin);   
}
